﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
//using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using DBConnectionLib;

namespace DBSourceToolsLib.SysObjects
{
    public enum SysObjectType
    {
        Table,
        View,
        Function,
        Proc,
        Querie,
        DataType,
        Schema,
        XmlSchema,
        User,
        Role,
        TableType,
        Trigger,
        Patche,
        Synonym
    }

    public abstract class SysObject : Interfaces.IDisplayPanel
    {
//        private string m_Text;
//        private string m_DBName;
        private string m_Name;
        private SysObjectType m_Type;
        private string m_BaseDirectory;
        private bool m_IsChanged= false;
        private string m_Urn;
        protected Database m_Database;
        StringCollection m_StringCollection = new StringCollection();
        // used to set DBExplorer treeview state;
        public bool IsExpanded;
        public virtual List<ColInfo> Columns /*only used for tables and views*/ { get { return null; } }

        public SysObject(string strName, string strBaseDirectory, Database oDatabase, SysObjectType soType)
        {
            this.m_Name = strName;
            this.Type = soType;
            this.BaseDirectory = strBaseDirectory;// +@"\" + oDatabase.Name; // this must not include db for clones.

            this.m_Database = oDatabase;
        }
        public SysObject(SysObjectType soType, string strFileName, Database oDatabase)
        {
            this.Type = soType;
            ParseFile(strFileName);
            this.m_Database = oDatabase;
//            this.DBName = oDatabase.Name;
        }

        //public abstract System.Windows.Forms.Panel getPanel();

        #region getters and setters
        public bool IsChanged
        {
            get { return m_IsChanged; }
        }

        public string QualifiedName
        {
            get { return this.Type.ToString() + "." + this.Name; }
        }

        public string GetFullyQualifiedName()
        {
            string strQuery = "";
            string[] strSplitResult;
            strSplitResult = this.Name.Split(new char[] { '.' });
            int countSplit = 0;
            foreach (string strFoundSplit in strSplitResult)
            {
                if (countSplit > 0)
                {
                    strQuery += ".";
                }
                strQuery += "[" + strFoundSplit + "]";
                countSplit++;
            }
            return strQuery;
        }

        public string DBName
        {
            get { return this.m_Database.DatabaseName; }
//            set { m_DBName = value; }
        }

        public string Text
        {
            get {
                StringBuilder oBuilder = new StringBuilder();
                foreach (string strLine in this.m_StringCollection)
                    oBuilder.AppendLine(strLine);
                return oBuilder.ToString();
            }
            set {
                
                foreach (string strLine in value.Split('\n'))
                {
                    this.m_StringCollection.Add(strLine);
                }
//                m_Text = value;
                this.m_IsChanged = true;
            }
        }

        public string BaseDirectory
        {
            get { return m_BaseDirectory; }
            set { m_BaseDirectory = value; }
        }

        public SysObjectType Type
        {
            get { return m_Type; }
            set { m_Type = value; }
        }

        public string Name
        {
            get {
                if (m_Name.Contains("\\"))
                    return m_Name.Replace('\\', '_');
                return m_Name; 
            }
            set
            {
                m_Name = value;
                if (m_Name.Contains("\\"))
                    m_Name = m_Name.Replace('\\', '_');
                this.m_IsChanged = true;
            }
        }

        public string NameNoSchema
        {
            get {
                if (this.Name.Contains("."))
                {
                    return this.Name.Substring(this.Name.IndexOf(".") + 1);
                } else
                    return m_Name; 
            }
        }
        public string Urn
        {
            get { return m_Urn; }
            set { m_Urn = value; }
        }

        #endregion 
        public string GetString()
        {
            return this.m_Type.ToString() + " " + this.m_Name;
        }

        public string UrnFileName
        {
            get
            {
                return this.BaseDirectory + "\\" + this.Type.ToString() + "s\\Urns\\" + this.Name + ".urn";
            }
        }

        public string FileName
        {
            get
            {
                return this.BaseDirectory + "\\" + this.Type.ToString() + "s\\" + this.Name + ".sql";
            }
        }

        public string ShortFileName
        {
            get
            {
                return this.Type.ToString() + "s\\" + this.Name + ".sql";
            }
        }

        protected virtual void WriteData(string strDirPath, string strOrderBy, bool isDeploymentTarget, bool bRefreshData)
        {
        }

        public void WriteFile()
        {
                // check if the directory exists
                if (!(this is SOQuery))
                    throw (new Exception("Only SOQuery can use WriteFile()"));
                string strDirPath = this.BaseDirectory + "\\" + this.Type.ToString() + "s";
                if (!System.IO.Directory.Exists(strDirPath))
                    System.IO.Directory.CreateDirectory(strDirPath);

                FileUtils.EnsureFileIsWriteable(this.FileName);
                    using (System.IO.StreamWriter sWriter = new System.IO.StreamWriter(this.FileName))
                    {
                        sWriter.Write(this.Text);
                    }
        }

        public void WriteFile(bool bWriteData, bool isDeploymentTarget, string strOrderBy, bool bRefreshData)
        {
            try
            {
                // check if the directory exists
                string strDirPath = this.BaseDirectory + "\\" + this.Type.ToString() + "s";
                if (!System.IO.Directory.Exists(strDirPath))
                    System.IO.Directory.CreateDirectory(strDirPath);

                if (!isDeploymentTarget)
                    this.LoadScript(this.m_Database, this.FileName);
                else
                {
                    FileUtils.EnsureFileIsWriteable(this.FileName);
                    using (System.IO.StreamWriter sWriter = new System.IO.StreamWriter(this.FileName))
                    {
                        sWriter.Write(this.Text);
                    }
                }

                string strUrnPath = strDirPath + "\\Urns";
                if (!System.IO.Directory.Exists(strUrnPath))
                    System.IO.Directory.CreateDirectory(strUrnPath);

                FileUtils.EnsureFileIsWriteable(this.UrnFileName);
                using (System.IO.StreamWriter sWriter = new System.IO.StreamWriter(this.UrnFileName))
                {
                    sWriter.Write(this.Urn);
                }

                if ((bWriteData) && (this.Type == SysObjectType.Table))
                {
                    // script table data
                    WriteData(strDirPath, strOrderBy, isDeploymentTarget, bRefreshData);

                }
            }
            catch (Exception ex)
            {
                // could not write file.
                throw new Exception(ex.ToString());
            }

        }


        protected void ParseFile(string strFullPath)
        {
            
            string strFile = strFullPath.Substring(strFullPath.LastIndexOf("\\")+ 1);
            
            string strName = strFile.Substring(0, strFile.IndexOf(".sql"));
            string strTypeAndFile = "\\" + this.Type.ToString() + "\\" + strFile;
            string strBaseDirectory = strFullPath.Substring(0, strFullPath.Length - (strTypeAndFile.Length+1));
            this.BaseDirectory = strBaseDirectory;
            this.m_Name = strName;
            if (System.IO.File.Exists(strFullPath))
            {
                using (System.IO.StreamReader oStreamReader = new System.IO.StreamReader(strFullPath))
                {
                    string strLine = oStreamReader.ReadLine();
                    while (strLine != null)
                    {
                        this.m_StringCollection.Add(strLine);
                        strLine = oStreamReader.ReadLine();
                    }
//                    this.m_Text = oStreamReader.ReadToEnd();
                }
            }
            if (System.IO.File.Exists(this.UrnFileName))
            {
                using (System.IO.StreamReader oStreamReader = new System.IO.StreamReader(this.UrnFileName))
                {
                    this.m_Urn = oStreamReader.ReadToEnd();
                }

            }
        }

        protected void SetTextFromScript(System.Collections.Specialized.StringCollection myStrColl)
        {
            StringBuilder oStringBuilder = new StringBuilder();

            foreach (string strLine in myStrColl)
            {
                this.m_StringCollection.Add(strLine);
            }

        }

        public abstract void LoadScript(Database oDatabase, string outputFileName);

        public void SetUrn(Database oDatabase)
        {
            Microsoft.SqlServer.Management.Smo.Server oServer;
            if (!System.String.IsNullOrEmpty(oDatabase.UserName))
            {
                Microsoft.SqlServer.Management.Common.ServerConnection oConn =
                    new Microsoft.SqlServer.Management.Common.ServerConnection(oDatabase.DataSourceName,
                        oDatabase.UserName, oDatabase.Password);
                oServer = new Microsoft.SqlServer.Management.Smo.Server(oConn);
            }
            else
            {
                oServer = new Microsoft.SqlServer.Management.Smo.Server(oDatabase.DataSourceName);
            }

            //            Microsoft.SqlServer.Management.Smo.Server oServer = new Microsoft.SqlServer.Management.Smo.Server(oDatabase.DataSourceName);
            Microsoft.SqlServer.Management.Smo.Database oMDatabase = oServer.Databases[oDatabase.DatabaseName];

            switch (this.Type)
            {
                case SysObjectType.Table:
                    Microsoft.SqlServer.Management.Smo.Table myTable = oMDatabase.Tables[this.NameNoSchema];
                    this.Urn = myTable.Urn.ToString();
                    break;
                case SysObjectType.DataType:
                    Microsoft.SqlServer.Management.Smo.UserDefinedDataType oSysObject = oMDatabase.UserDefinedDataTypes[this.NameNoSchema];
                    this.Urn = oSysObject.Urn.ToString();
                    break;
                case SysObjectType.Proc:
                    Microsoft.SqlServer.Management.Smo.StoredProcedure oProc = oMDatabase.StoredProcedures[this.NameNoSchema];
                    this.Urn = oProc.Urn.ToString();
                    break;

            }
            

        }

        public void SetTextFromFile(string strFileName)
        {
            if (System.IO.File.Exists(strFileName))
            {
                using (System.IO.StreamReader oStreamReader = new System.IO.StreamReader(strFileName))
                {
                    string strLine = oStreamReader.ReadLine();
                    while (strLine != null)
                    {
                        this.m_StringCollection.Add(strLine);
                        strLine = oStreamReader.ReadLine();
                    }
                }

            }
            
        }



        #region IDisplayPanel Members

        public abstract System.Windows.Forms.Panel GetPanel();

        #endregion

        protected void EnsureDirectoryExists(string outputFileName)
        {
            FileUtils oFileUtils = new FileUtils();
            oFileUtils.EnsureFileDirectoryExists(outputFileName);
        }

        protected void AddDropScriptToFile(string strOutputFileName, StringCollection strDropColl)
        {
            StringBuilder oBuilder = new StringBuilder();
            foreach (string strDropLine in strDropColl)
            {
                oBuilder.AppendLine(strDropLine);
            }
            oBuilder.AppendLine("GO");
            using (System.IO.StreamReader oStreamReader = new System.IO.StreamReader(strOutputFileName))
            {
                oBuilder.Append(oStreamReader.ReadToEnd());
            }
            FileUtils.EnsureFileIsWriteable(strOutputFileName);
            using (System.IO.StreamWriter oStreamWriter = new System.IO.StreamWriter(strOutputFileName))
            {
                oStreamWriter.Write(oBuilder.ToString());
            }
        }

        public bool SearchText( SearchEngine searchEngine, /*string strSearchTerm, 
                bool skipComments, bool matchTheWholeWord,*/
                ref List< SearchResultLine> oResultsList)
        {
            oResultsList.Clear();
            oResultsList = searchEngine.Search( this.m_StringCollection );
            return ( oResultsList.Count > 0 );

            //bool found = false;
            //oResultsList.Clear();
            //for ( int i = 0; i < this.m_StringCollection.Count; i++ )
            //{
            //    if (this.m_StringCollection[i].ToLower().Contains(strSearchTerm.ToLower()))
            //    {
            //        found = true;
            //        SearchResultLine oResultLine = new SearchResultLine(i+1, this.m_StringCollection[i]);
            //        oResultsList.Add(oResultLine);
            //    }
            //}
            //return found;
        }

        public abstract Composite.DBComposite GetDBComposite();
    }
}
